package com.roadmap.util.upload;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;

import com.roadmap.common.BaseConst;
import com.roadmap.struts.action.ActionConst;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/* the picture to be loaded will be changed to a fixed size and generate two copies under specified path.*/
public class PurikuraUpload extends SmartUpload {
	/** where the purikura is placed temporarily */
	private final static String Purikura_Temp_Path = BaseConst.PURIKURA_DIR_TEMP;
	/** where the big purikura is placed */
	private final static String Purikura_Big_Path = BaseConst.PURIKURA_DIR_BIG;
	/** where the small purikura is placed */
	private final static String Purikura_Small_Path = BaseConst.PURIKURA_DIR_SMALL;

	private final static String Image_Suffix = ".gif";

	private final static int HEAD_IMAGE_WIDTH_BIG = 170;
	private final static int HEAD_IMAGE_HEIGHT_BIG = 300;
	private final static int HEAD_IMAGE_WIDTH_SMALL = 60;
	private final static int HEAD_IMAGE_HEIGHT_SMALL = 60;

	private final static Set<String> imageSuffixes = new HashSet<String>();

	static {
		imageSuffixes.add(".jpg");
		imageSuffixes.add(".jpeg");
		imageSuffixes.add(".gif");
		imageSuffixes.add(".tif");
		imageSuffixes.add(".png");
		imageSuffixes.add(".bmp");
	}

	@Override
	public void upload() throws ServletException, IOException,
			SmartUploadException {
		if (m_application == null) {
			throw new SmartUploadException(
					"the uploaded process should be initialized firstly");
		}

		long l = 0L;
		m_totalBytes = m_request.getContentLength();
		m_binArray = new byte[m_totalBytes];
		// m_request.getInputStream().read(m_binArray);
		for (int i = 0, j = 0; i < m_totalBytes; i += j) {
			try {
				j = m_request.getInputStream().read(m_binArray, i,
						m_totalBytes - i);
				// System.out.println(new String(m_binArray));
			}
			catch (Exception e) {
				throw new SmartUploadException(
						"failed to read servlet input stream");
			}
		}

		for (; m_currentIndex < m_totalBytes; m_currentIndex++) {
			// 13 - enter key
			if (m_binArray[m_currentIndex] == 13) {
				break;
			}
			else {
				m_boundary = m_boundary + (char) m_binArray[m_currentIndex];
			}
		}
		if (m_currentIndex == 1) {
			throw new SmartUploadException("input stream is invalid");
		}

		// System.out.println(new String(m_binArray, 0, 300));

		String dataHead = getDataHeader();
		String fieldName = getDataFieldValue(dataHead, "name");
		m_currentIndex = m_currentIndex + 2;

		if (dataHead.indexOf("filename") == 0) {
			throw new SmartUploadException(
					"Invalid request. can't find the property 'fieldname'");
		}

		String filePath = getDataFieldValue(dataHead, "filename"); // file path
		String fileName = getFileName(filePath); // m_request.getParameter(fieldName); // file name
		if(fileName == null || fileName.trim().equals("")){
			throw new SmartUploadException("the file name is invalid");
		}
		
		String fileExt = getFileExt(fileName); // file extension

		getDataSection();

		if (m_maxFileSize <= 0L
				|| (long) ((m_endData - m_startData) + 1) > m_maxFileSize) {
			throw new SecurityException("Size exceeded for this file : "
					+ fileName + " (1105).");
		}
		l += (m_endData - m_startData) + 1;
		if (m_totalMaxFileSize > 0L && l > m_totalMaxFileSize) {
			throw new SecurityException("Total File Size exceeded.");
		}
		else if(l <= 1){
			throw new SecurityException("Total File Size is less than 0.");
		}

		String fileType = getContentType(dataHead);
		String fileDesc = getContentDisp(dataHead);
		String mimeType = getTypeMIME(fileType);
		String subMimeType = getSubTypeMIME(fileType);

		File file = new File();
		file.setParent(this);
		file.setFieldName(fieldName);
		String fn = System.currentTimeMillis() + "_" + fileName;
		file.setFileName(fn);
		file.setFilePathName(fn);
		file.setFileExt(fileExt);
		file.setIsMissing(filePath.length() == 0);
		file.setContentType(fileType);
		file.setContentDisp(fileDesc);
		file.setTypeMIME(mimeType);
		file.setSubTypeMIME(subMimeType);

		if (fileType.indexOf("application/x-macbinary") > 0) {
			m_startData = m_startData + 128;
		}
		file.setSize((m_endData - m_startData) + 1);
		file.setStartData(m_startData);
		file.setEndData(m_endData);
		m_files.addFile(file);
	}

	public int save() throws ServletException, IOException,
			SmartUploadException {
		// the flag indicates the uploading an image is successfully.
		int saveFlag = 0;

		if (m_application == null) {
			throw new SmartUploadException(
					"the uploaded process should be initialized firstly");
		}

		// the new file names are the UID
		String uid = (String) m_request.getSession().getAttribute(ActionConst.Aspirant_Id_In_Session);
		if (uid == null) {
			throw new SmartUploadException("the user is not logged on.");
		}

		if (m_files.getCount() != 1) {
			throw new SmartUploadException(
					"the uploaded images should be only one copy");
		}

		String saveDir = Purikura_Temp_Path;
		if (saveDir.indexOf("/") != -1) {
			if (saveDir.charAt(saveDir.length() - 1) != '/') {
				saveDir = saveDir + "/";
			}
		}
		else {
			if (saveDir.charAt(saveDir.length() - 1) != '\\') {
				saveDir = saveDir + "\\";
			}
		}

		// save the image to the server
		File file = m_files.getFile(0);
		String filePath = saveDir + file.getFileName();
		file.saveAs(filePath);

		// resize the image
		// get the local path of the uploaded image on the server
		String appDir = m_application.getRealPath("/");
		java.io.File nf = new java.io.File(appDir + filePath);
		if (nf.exists() && nf.isFile()) {
			try {
				String savedFile = appDir + Purikura_Big_Path + uid
						+ Image_Suffix;
				resizeImage(nf, HEAD_IMAGE_WIDTH_BIG, HEAD_IMAGE_HEIGHT_BIG, savedFile);

				savedFile = appDir + Purikura_Small_Path + uid + Image_Suffix;
				resizeImage(nf, HEAD_IMAGE_WIDTH_SMALL, HEAD_IMAGE_HEIGHT_SMALL, savedFile);

				saveFlag = 1;
			}
			catch (IOException e) {
				e.printStackTrace();
			}
			finally {
				// delete the original image
				nf.delete();
			}
		}
		else {
			new Exception("could find the uploaded image");
		}

		return saveFlag;
	}

	/**
	 * reset the size of the images
	 * 
	 * @throws IOException
	 */
	private void resizeImage(java.io.File file, int maxWidth, int maxHeight, String savedFile)
			throws IOException {
		if (file == null || maxWidth <= 0 || maxHeight <= 0 || savedFile == null) {
			return;
		}

		Image image = ImageIO.read(file);
		if (image == null) {
			throw new SecurityException("Invalid image!");
		}
		int imgW = image.getWidth(null);
		int imgH = image.getHeight(null);
		int[] size = getZoomIn(imgW, imgH, maxWidth, maxHeight);
		BufferedImage bufferedImage = new BufferedImage(size[0], size[1],
				BufferedImage.TYPE_INT_RGB);
		bufferedImage.getGraphics().drawImage(image, 0, 0, size[0], size[1],
				null);
		FileOutputStream fos = new FileOutputStream(savedFile);
		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fos);
		encoder.encode(bufferedImage);
		fos.close();
	}

	/** zoom in the image, actually resize its width */
	private int[] getZoomIn(int width, int height, int maxw, int maxh) {
		int[] size = { width, height };
		if (width > maxw) {
			double scale = (1.0 * maxw) / width;
			size[0] = (int) (width * scale);
			size[1] = (int) (height * scale);
			
			if(size[1] > maxh){
				scale = (1.0 * maxh) / height;
				size[0] = (int) (width * scale);
				size[1] = (int) (height * scale);
			}
		}
		return size;
	}
}
